package com.copm.ifm.common.process.entity.define.vo;

import com.copm.ifm.common.process.core.annotation.ConditionInclude;
import com.copm.ifm.common.process.core.emum.ExaminePersonType;
import com.copm.ifm.common.process.core.emum.ExamineTypeEnum;
import com.copm.ifm.common.process.entity.ProcessProperty;
import com.copm.ifm.common.process.entity.define.ConditionFieldDefine;
import com.copm.ifm.common.process.entity.define.ProcessDefine;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 流程定义列表接口返回对象
 *
 * @author zzf
 * @date 2021/4/7 8:58
 */
@Data
@Accessors(chain = true)
@ApiModel("流程定义列表接口返回对象")
public class ProcessDefineVO implements Serializable {

    @ApiModelProperty("名称")
    private String name;

    @ApiModelProperty("编号")
    private String code;

    @ApiModelProperty(value = "关联实体类中作为条件的字段信息", notes = "key: fieldName， value: fieldComment")
    private List<ConditionFieldDefine> conditionFieldList;

    @ApiModelProperty(value = "审核人员类型", notes = "key: id(用于传参), value: name(用于展示)")
    private Set<ExaminePersonType> examinePersonType;

    @Getter
    @Setter
    @ApiModelProperty("前端打开流程时触发操作")
    private String eventAtOpen;

    @Getter
    @Setter
    @ApiModelProperty("前端关闭流程时触发操作")
    private String eventAtClose;

    @Getter
    @Setter
    @ApiModelProperty("打开流程时触发操作")
    private String afterFinish;

    @Getter
    @Setter
    @ApiModelProperty("打开流程时触发操作")
    private String beforeBegin;


    public static ProcessDefineVO covertByBO(ProcessDefine<?> processDefine) {
        ProcessDefineVO processDefineVO = new ProcessDefineVO();

        processDefineVO.setName(processDefine.getName())
                .setCode(processDefine.getCode())
                .setEventAtClose(processDefine.getEventAtClose())
                .setEventAtOpen(processDefine.getEventAtOpen())
                .setAfterFinish(processDefine.getAfterFinish())
                .setBeforeBegin(processDefine.getBeforeBegin())
                .setConditionFieldList(getConditionFieldList(processDefine))
                .setExaminePersonType(getExaminePersonType(processDefine));

        return processDefineVO;

    }

    private static List<ConditionFieldDefine> getConditionFieldList(ProcessDefine<?> processDefine) {
        List<ConditionFieldDefine> conditionFieldList = new ArrayList<>(40);
        conditionFieldList.addAll(
                getFieldMapForCondition(
                        processDefine.getTargetClass(),
                        ExamineTypeEnum.TARGET_FIELD.getType()
                )
        );
        conditionFieldList.addAll(
                getFieldMapForCondition(
                        processDefine.getProcessProperty().getUserClass(),
                        ExamineTypeEnum.USER_FIELD.getType()
                )
        );
        return conditionFieldList;
    }


    private static Set<ExaminePersonType> getExaminePersonType(ProcessDefine<?> processDefine) {
        Set<ExaminePersonType> examinePersonType = new HashSet<>();

        Optional.of(processDefine.getEntityFieldPersonGetters())
                .ifPresent(i -> i.forEach(s -> examinePersonType.add(s.getExaminePersonType())));

        Optional.of(processDefine.getProcessProperty())
                .map(ProcessProperty::getExaminePersonGetters)
                .ifPresent(i -> i.forEach(s -> examinePersonType.add(s.getExaminePersonType())));

        return examinePersonType;

    }


    /**
     * 获取指定类中用于条件的字段map
     *
     * @param entityClass 实体类
     * @return 用于条件的字段map
     */
    private static List<ConditionFieldDefine> getFieldMapForCondition(Class<?> entityClass, Integer targetType) {

        if (entityClass == null) {
            return new ArrayList<>();
        }
        List<ConditionFieldDefine> fieldList = new ArrayList<>(20);
        boolean hadAnnotation = entityClass.isAnnotationPresent(ConditionInclude.class);
        for (Field field : entityClass.getDeclaredFields()) {
            if ((!hadAnnotation && field.isAnnotationPresent(ConditionInclude.class))
                    || (hadAnnotation && !field.isAnnotationPresent(ConditionInclude.class))) {
                String fieldComment;
                if (field.isAnnotationPresent(ApiModelProperty.class)) {
                    ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
                    fieldComment = annotation.value();
                } else {
                    fieldComment = field.getName();
                }
                ConditionFieldDefine fieldDefine = new ConditionFieldDefine();
                fieldDefine.setFieldComment(fieldComment);
                fieldDefine.setFieldName(field.getName());
                fieldDefine.setFieldType(field.getType().getSimpleName());
                fieldDefine.setTargetType(targetType);

                fieldList.add(fieldDefine);
            }

        }
        return fieldList;
    }

}
